package com.fowo.api.sys.ssf.impl;

import com.fowo.api.common.util.ListUtils;
import com.fowo.api.sys.ssf.SimpleStatusFlowService;
import com.fowo.api.sys.ssf.def.SimpleStatusFlowDef;
import com.fowo.api.sys.ssf.def.SimpleStatusFlowDefs;
import com.fowo.api.sys.ssf.entity.SysStatusFlow;
import com.fowo.api.sys.ssf.mapper.SysStatusFlowMapper;
import com.fowo.api.sys.ssf.model.SimpleStatusFlowGraph;
import com.fowo.api.sys.ssf.model.SimpleStatusFlowGraphItem;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 简单状态流服务实现
 * @author yl_ls
 */
@Service
public class SimpleStatusFlowServiceImpl implements SimpleStatusFlowService {
    @Resource
    private SysStatusFlowMapper sysStatusFlowMapper;
    @Resource
    private SimpleStatusFlowDefs simpleStatusFlowDefs;

    @Override
    public SimpleStatusFlowGraph getGraph(String objectName, Long id) {
        SimpleStatusFlowDef flowDef = simpleStatusFlowDefs.getFlowDef(objectName);
        if (flowDef == null) {
            return null;
        }
        SimpleStatusFlowGraph flowGraph = new SimpleStatusFlowGraph();
        flowGraph.setItems(new ArrayList<>());
        List<SysStatusFlow> statusFlows = id == null ? Collections.emptyList() : sysStatusFlowMapper.selectGraph(objectName, id);
        mixGraph(flowGraph, flowDef, statusFlows);
        return flowGraph;
    }

    private void mixGraph(SimpleStatusFlowGraph flowGraph, SimpleStatusFlowDef flowDef, List<SysStatusFlow> statusFlows) {
        int maxDefIndex = -1;
        String lastStatusValue = "";
        Set<String> runStatus = new HashSet<>();
        for (SysStatusFlow statusFlow : statusFlows) {
            int itemIndex = ListUtils.findIndex(flowDef.getItems(), i -> Objects.equals(i.getId(), statusFlow.getDefId()));
            if (itemIndex > maxDefIndex) {
                maxDefIndex = itemIndex;
            }
            SimpleStatusFlowGraphItem graphItem = new SimpleStatusFlowGraphItem();
            BeanUtils.copyProperties(statusFlow, graphItem);
            flowGraph.getItems().add(graphItem);
            runStatus.add(statusFlow.getStatus());
            lastStatusValue = statusFlow.getStatus();
        }
        while (StringUtils.hasText(lastStatusValue)) {
            String finalLastStatusValue = lastStatusValue;
            List<SimpleStatusFlowDef.Item> nextDefItems = flowDef.getItems().stream().filter(i -> Objects.equals(finalLastStatusValue, i.getOldValue())).collect(Collectors.toList());
            if (nextDefItems.isEmpty()) {
                return;
            }
            if (nextDefItems.size() > 1) {
                SimpleStatusFlowGraphItem graphItem = new SimpleStatusFlowGraphItem();
                graphItem.setTitle(nextDefItems.stream().map(SimpleStatusFlowDef.Item::getTitle).collect(Collectors.joining(" / ")));
                flowGraph.getItems().add(graphItem);
                return;
            }
            SimpleStatusFlowDef.Item itemDef = nextDefItems.get(0);
            if (runStatus.contains(itemDef.getNewValue())) {
                // 重复会死循环，跳出
                return;
            }
            SimpleStatusFlowGraphItem graphItem = new SimpleStatusFlowGraphItem();
            BeanUtils.copyProperties(itemDef, graphItem, "id");
            graphItem.setDefId(itemDef.getId());
            flowGraph.getItems().add(graphItem);
            runStatus.add(itemDef.getNewValue());
            lastStatusValue = itemDef.getNewValue();
        }
    }

    @Override
    public void afterCreate(String objectName, String operator, Long id, String status) {
        SimpleStatusFlowDef flowDef = simpleStatusFlowDefs.getFlowDef(objectName);
        if (flowDef == null) {
            return;
        }
        flowDef.getItems().stream().filter(i -> Objects.equals(status, i.getNewValue()) && (!StringUtils.hasText(i.getOldValue()) || "*".equals(i.getOldValue()))).findFirst().ifPresent(def -> {
            writeStatusFlow(operator, id, flowDef, def);
        });
    }

    @Override
    public void afterUpdate(String objectName, String operator, Long id, String oldStatus, String newStatus) {
        if (Objects.equals(oldStatus, newStatus)) {
            // 状态值没有变更，无需处理
            return;
        }
        SimpleStatusFlowDef flowDef = simpleStatusFlowDefs.getFlowDef(objectName);
        if (flowDef == null) {
            return;
        }
        flowDef.getItems().stream().filter(i -> Objects.equals(newStatus, i.getNewValue()) && (Objects.equals(oldStatus, i.getOldValue()) || "*".equals(i.getOldValue()))).findFirst().ifPresent(def -> {
            writeStatusFlow(operator, id, flowDef, def);
        });
    }

    private void writeStatusFlow(String operator, Long id, SimpleStatusFlowDef flowDef, SimpleStatusFlowDef.Item def) {
        SysStatusFlow newFlow = new SysStatusFlow();
        newFlow.setObjectName(flowDef.getObjectName());
        newFlow.setObjectId(id);
        newFlow.setDefId(def.getId());
        newFlow.setStatus(def.getNewValue());
        newFlow.setCreateTime(new Date());
        newFlow.setTitle(def.getTitle());
        newFlow.setDescription(def.getDescription());
        newFlow.setDelFlag(false);
        newFlow.setOperator(operator);
        sysStatusFlowMapper.insert(newFlow);
    }
}
